package com.wuyan.web.auth.service;

import com.querydsl.core.QueryResults;
import com.querydsl.core.types.OrderSpecifier;
import com.querydsl.core.types.Predicate;
import com.querydsl.core.types.dsl.PathBuilder;
import com.querydsl.jpa.impl.JPAQuery;
import com.querydsl.jpa.impl.JPAQueryFactory;
import com.querydsl.jpa.impl.JPAUpdateClause;
import com.wuyan.web.base.helper.PageHelper;
import com.wuyan.web.base.helper.ReflexHelper;
import com.wuyan.web.base.helper.entity.EntityFieldInfo;
import com.wuyan.web.base.helper.rep.RepPageData;
import com.wuyan.web.base.helper.req.CustomQueryHelper;
import com.wuyan.web.base.helper.req.CustomQueryParams;
import com.wuyan.web.base.helper.req.CustomQueryOrderParams;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.wuyan.web.auth.entity.PubConfig;
import com.wuyan.web.auth.entity.QPubConfig;
import com.wuyan.web.auth.repo.PubConfigRepo;
import com.wuyan.web.auth.form.PubConfigForm;
import org.springframework.transaction.annotation.Transactional;
import lombok.extern.slf4j.Slf4j;

import com.wuyan.web.base.helper.DataEncryptionHelper;
import static com.wuyan.web.base.config.EntityConfig.DATA_ENCRYPTION;
import static com.wuyan.web.base.config.EntityConfig.ER_BATCH_INSERT_ON_CLEAR;


import javax.annotation.PostConstruct;
import javax.persistence.EntityManager;
import javax.persistence.PersistenceContext;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import java.util.ArrayList;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import java.time.LocalDateTime;


/**
 * service for PubConfig generated by jpa-codegen
 * TODO
 *
 * @author wuyan
 * @date 2021-06-07 18:44:13
 */

@Slf4j
@Service
public class PubConfigService {

    @Autowired
    private PubConfigRepo pubConfigRepo;

    @Autowired
    @PersistenceContext
    private EntityManager entityManager;

    private JPAQueryFactory queryFactory;

    @PostConstruct
    public void init() {
        queryFactory = new JPAQueryFactory(entityManager);
    }

    /**
     * 创建实体
     *
     * @param form 表单
     * @return 实体对象
     */
    @Transactional(rollbackFor = Exception.class)
    public PubConfig create(PubConfigForm form) throws Exception {
        // 特殊处理：加密
        DataEncryptionHelper.encode("pubConfig", form, DATA_ENCRYPTION);

        PubConfig pubConfig = PubConfig.builder().build();
        BeanUtils.copyProperties(form, pubConfig);

        pubConfig.setCfgModify(1);
        pubConfig.setCreateTime(LocalDateTime.now());

        return pubConfigRepo.save(pubConfig);
    }

    /**
    * 创建实体-批量
    * 根据 EntityConfig.ER_BATCH_INSERT_ON_CLEAR判断是否需要执行对应的清除操作
    *
    * @param forms 表单集合
    */
    @Transactional(rollbackFor = Exception.class)
    public List<PubConfig> creates(List<PubConfigForm> forms) throws Exception {
        List<PubConfig> res = new ArrayList<>();

        // 根据ER_BATCH_INSERT_ON_CLEAR匹配是否在批量插入时执行清空操作
        String key = "pubConfig";
        if (ER_BATCH_INSERT_ON_CLEAR.containsKey(key) && forms.size() > 0) {
            EntityFieldInfo<Integer> entityFieldInfo = ER_BATCH_INSERT_ON_CLEAR.get(key);
            PubConfigForm pubConfigForm = forms.get(0);

            try {
                // 匹配查询条件
                Integer value = ReflexHelper.getFieldValue(pubConfigForm, entityFieldInfo.getName(), entityFieldInfo.getClz());
                List<CustomQueryParams> paramsList = new ArrayList<>();
                Integer[] right = {value};
                paramsList.add(CustomQueryParams.builder().left(entityFieldInfo.getName()).op("eq").right(right).build());

                QPubConfig q = QPubConfig.pubConfig;
                PathBuilder<PubConfig> pathBuilder = new PathBuilder<>(PubConfig.class, q.getMetadata());

                // 构建查询条件
                CustomQueryHelper<PubConfig> customQueryHelper = CustomQueryHelper.<PubConfig>builder()
                        .paramsList(paramsList)
                        .pathBuilder(pathBuilder)
                        .entityClass(PubConfig.class)
                        .build()
                        .structure();

                // 先查询，再删除
                List<PubConfig> deleteAll = queryFactory.select(q).from(q)
                        .where(customQueryHelper.getPredicates().toArray(new Predicate[0]))
                        .fetch();

                Integer[] ids = deleteAll.stream()
                        .map(PubConfig::getId)
                        .toArray(Integer[]::new);
                delete(ids);
            } catch (IllegalAccessException e) {
                log.error("查询列：" + entityFieldInfo.getName() + "非法访问。" + e.getMessage());
            } catch (NoSuchMethodException e) {
                log.error("查询列：" + entityFieldInfo.getName() + "不存在此方法。" + e.getMessage());
            } catch (InvocationTargetException e) {
                log.error("查询列：" + entityFieldInfo.getName() + "调用方法时错误。" + e.getMessage());
            } catch (Exception e) {
                log.error(e.getMessage(), e);
            }
        }

        for (PubConfigForm form : forms) {
            res.add(create(form));
        }

        return res;
    }

    /**
     * 删除实体
     *
     * @param id 需要被删除的行ID组
     */
    @Transactional(rollbackFor = Exception.class)
    public Integer delete(Integer[] id) {
        List<PubConfig> all = pubConfigRepo.findAllById(Arrays.asList(id));

        if(all.isEmpty()){
            return null;
        }

        List<Integer> ids = all.stream()
            .filter(t -> t.getCfgModify() == 1)
            .map(PubConfig::getId)
            .collect(Collectors.toList());

        return pubConfigRepo.deleteAll(ids);
    }

    /**
     * 更新实体
     *
     * @param form 表单
     * @param id      实体id
     * @return 实体对象
     */
    @Transactional(rollbackFor = Exception.class)
    public Optional<PubConfig> update(PubConfigForm form, Integer id)  throws Exception {
            // 特殊处理：加密
            DataEncryptionHelper.encode("pubConfig", form, DATA_ENCRYPTION);

            return pubConfigRepo.findById(id)
                .filter(t -> t.getCfgModify() == 1)
                .map(pubConfig -> {
                    BeanUtils.copyProperties(form, pubConfig);


                    return pubConfigRepo.save(pubConfig);
                });
    }

    /**
    * 根据ID更新指定字段的值
    *
    * @param id    ID
    * @param field 字段名
    * @param value 字段值
    * @return long
    */
    @Transactional(rollbackFor = Exception.class)
    public long updateByField(Integer id, String field, String value) throws Exception {
        List<EntityFieldInfo<?>> entityFieldInfoList = DATA_ENCRYPTION.get("pubConfig");
        value = DataEncryptionHelper.encode(field, value, entityFieldInfoList);

        QPubConfig q = QPubConfig.pubConfig;
        PathBuilder<PubConfig> pathBuilder = new PathBuilder<>(PubConfig.class, q.getMetadata());

        List<CustomQueryParams> paramsList = new ArrayList<>();
            paramsList.add(CustomQueryParams.builder()
            .left("id")
            .op("eq")
            .right(new Integer[]{id})
            .build());
            List<CustomQueryOrderParams> orderList = new ArrayList<>();

        // 构建查询条件
        CustomQueryHelper<PubConfig> customQueryHelper = CustomQueryHelper.<PubConfig>builder()
                .paramsList(paramsList)
                .pathBuilder(pathBuilder)
                .paramsOrders(orderList)
                .entityClass(PubConfig.class)
                .build()
                .structure();

        JPAUpdateClause update = queryFactory.update(q);
        JPAUpdateClause set = customQueryHelper.setJPAUpdateClause(update, field, value);
        JPAUpdateClause where = set.where(customQueryHelper.getPredicates().toArray(new Predicate[0]));

        return where.execute();
    }

    /**
     * 获取一个实体对象
     *
     * @param id 实体id
     * @return 实体对象
     */
    public Optional<PubConfig> get(Integer id) {
        return pubConfigRepo.findById(id);
    }

    /**
    * 分页接口
    *
    * @param predicates 查询条件
    * @param orderSpecifiers 排序
    * @param isPage 是否分页
    * @param page 当前页
    * @param limit 每页大小
    * @return 分页结果
    */
    public RepPageData<PubConfig> page(List<Predicate> predicates, List<OrderSpecifier<?>> orderSpecifiers, Boolean isPage, Integer page, Integer limit) {
        QPubConfig q = QPubConfig.pubConfig;
        JPAQuery<PubConfig> from = queryFactory.select(q).from(q);

        if(predicates != null && !predicates.isEmpty()){
            from = from.where(predicates.toArray(new Predicate[0]));
        }

        if(orderSpecifiers != null && !orderSpecifiers.isEmpty()){
            from = from.orderBy(orderSpecifiers.toArray(new OrderSpecifier[0]));
        }

        // 分页或者返回全部
        if (isPage != null && isPage) {
            QueryResults<PubConfig> pubConfigQueryResults = from
                    .offset((page - 1) * limit)
                    .limit(limit)
                    .fetchResults();
            return PageHelper.pageResp(pubConfigQueryResults, page, limit);
        } else {
            List<PubConfig> pubConfigQueryResults = from.fetch();
            return RepPageData.<PubConfig>builder()
                    .list(pubConfigQueryResults)
                    .page(1)
                    .limit(pubConfigQueryResults.size())
                    .build();
        }
    }
}